agora inbox for [email protected]  
help / color / mirror / Atom feed
Some shared memory chunks are allocated even if related processes won't start
2390+ messages / 6 participants
[nested] [flat]

* 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ messages in thread

* [PATCH v53 1/7] Introduce an option to make logical replication database specific.
@ 2026-04-04 15:16  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Antonin Houska @ 2026-04-04 15:16 UTC (permalink / raw)

By default, the logical decoding assumes access to shared catalogs, so the
snapshot builder needs to consider cluster-wide XIDs during startup. That in
turn means that, if any transaction is already running (and has XID assigned),
the snapshot builder needs to wait for its completion, as it does not know if
that transaction performed catalog changes earlier.

Possible problem with this concept is that if REPACK (CONCURRENTLY) is running
in some database, backends running the same command in other databases get
stuck until the first one has committed. Thus only as single backend in the
cluster can run REPACK (CONCURRENTLY) at any time. Likewise, REPACK
(CONCURRENTLY) can block walsenders starting on behalf of subscriptions
throughout the cluster.

This patch adds a new option to logical replication output plugin, to declare
that it does not use shared catalogs (i.e. catalogs that can be changed by
transactions running in other databases in the cluster). In that case, no
snapshot the backend will use during the decoding needs to contain information
about transactions running in other databases. Thus the snapshot builder only
needs to wait for completion of transactions in the current database.

Currently we only use this option in the REPACK background worker. It could
possibly be used in the plugin for logical replication too, however that would
need thorough analysis of that plugin.

The patch bumps WAL version number, due to a new field in xl_running_xacts.
---
 contrib/pg_visibility/pg_visibility.c       |  4 +-
 doc/src/sgml/logicaldecoding.sgml           |  4 ++
 src/backend/access/index/genam.c            |  8 +++
 src/backend/access/rmgrdesc/standbydesc.c   |  2 +
 src/backend/access/transam/xlog.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c      |  2 +-
 src/backend/postmaster/bgwriter.c           |  2 +-
 src/backend/replication/logical/decode.c    |  8 ++-
 src/backend/replication/logical/logical.c   |  3 ++
 src/backend/replication/logical/snapbuild.c | 59 ++++++++++++++++++---
 src/backend/replication/slot.c              |  2 +-
 src/backend/storage/ipc/procarray.c         | 23 +++++++-
 src/backend/storage/ipc/standby.c           | 14 ++++-
 src/include/access/genam.h                  |  7 +++
 src/include/access/xlog_internal.h          |  2 +-
 src/include/replication/output_plugin.h     |  1 +
 src/include/replication/snapbuild.h         |  3 +-
 src/include/storage/procarray.h             |  2 +-
 src/include/storage/standby.h               |  3 +-
 src/include/storage/standbydefs.h           |  1 +
 20 files changed, 131 insertions(+), 21 deletions(-)

diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dfab0b64cf5..d564bd2a00c 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -621,7 +621,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel)
 	else if (rel == NULL || rel->rd_rel->relisshared)
 	{
 		/* Shared relation: take into account all running xids */
-		runningTransactions = GetRunningTransactionData();
+		runningTransactions = GetRunningTransactionData(InvalidOid);
 		LWLockRelease(ProcArrayLock);
 		LWLockRelease(XidGenLock);
 		return runningTransactions->oldestRunningXid;
@@ -632,7 +632,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel)
 		 * Normal relation: take into account xids running within the current
 		 * database
 		 */
-		runningTransactions = GetRunningTransactionData();
+		runningTransactions = GetRunningTransactionData(InvalidOid);
 		LWLockRelease(ProcArrayLock);
 		LWLockRelease(XidGenLock);
 		return runningTransactions->oldestDatabaseRunningXid;
diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml
index 6dc49108997..28089d1053c 100644
--- a/doc/src/sgml/logicaldecoding.sgml
+++ b/doc/src/sgml/logicaldecoding.sgml
@@ -959,6 +959,7 @@ typedef struct OutputPluginOptions
 {
     OutputPluginOutputType output_type;
     bool        receive_rewrites;
+    bool        need_shared_catalogs;
 } OutputPluginOptions;
 </programlisting>
       <literal>output_type</literal> has to either be set to
@@ -969,6 +970,9 @@ typedef struct OutputPluginOptions
       also be called for changes made by heap rewrites during certain DDL
       operations.  These are of interest to plugins that handle DDL
       replication, but they require special handling.
+      <literal>need_shared_catalogs</literal> can be set to false if you are
+      sure the plugin functions do not access shared system catalogs. It can
+      speed up creation of replication slots that use this plugin.
      </para>
 
      <para>
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 1408989c568..44df2605068 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -394,6 +394,14 @@ systable_beginscan(Relation heapRelation,
 	SysScanDesc sysscan;
 	Relation	irel;
 
+	/*
+	 * If this backend promised that it won't access shared catalogs during
+	 * logical decoding, this seems to be the right place to check.
+	 */
+	Assert(!HistoricSnapshotActive() ||
+		   accessSharedCatalogsInDecoding ||
+		   !heapRelation->rd_rel->relisshared);
+
 	if (indexOK &&
 		!IgnoreSystemIndexes &&
 		!ReindexIsProcessingIndex(indexId))
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index 0a291354ae2..685d1bdb024 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -41,6 +41,8 @@ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
 		for (i = 0; i < xlrec->subxcnt; i++)
 			appendStringInfo(buf, " %u", xlrec->xids[xlrec->xcnt + i]);
 	}
+
+	appendStringInfo(buf, "; dbid: %u", xlrec->dbid);
 }
 
 void
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9e8999bbb61..1a6c1456d2c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7731,7 +7731,7 @@ CreateCheckPoint(int flags)
 	 * recovery we don't need to write running xact data.
 	 */
 	if (!shutdown && XLogStandbyInfoActive())
-		LogStandbySnapshot();
+		LogStandbySnapshot(InvalidOid);
 
 	START_CRIT_SECTION();
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 65bbaeda59c..0f5979691e6 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -245,7 +245,7 @@ pg_log_standby_snapshot(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("pg_log_standby_snapshot() can only be used if \"wal_level\" >= \"replica\"")));
 
-	recptr = LogStandbySnapshot();
+	recptr = LogStandbySnapshot(InvalidOid);
 
 	/*
 	 * As a convenience, return the WAL location of the last inserted record
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 1d8947774a9..a30de4262eb 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -289,7 +289,7 @@ BackgroundWriterMain(const void *startup_data, size_t startup_data_len)
 			if (now >= timeout &&
 				last_snapshot_lsn <= GetLastImportantRecPtr())
 			{
-				last_snapshot_lsn = LogStandbySnapshot();
+				last_snapshot_lsn = LogStandbySnapshot(InvalidOid);
 				last_snapshot_ts = now;
 			}
 		}
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 57aaef57c61..4299d0bc867 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -381,7 +381,13 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 			{
 				xl_running_xacts *running = (xl_running_xacts *) XLogRecGetData(r);
 
-				SnapBuildProcessRunningXacts(builder, buf->origptr, running);
+
+				/*
+				 * If the plugin does not access shared catalogs, only keep
+				 * track of transactions in the current database.
+				 */
+				SnapBuildProcessRunningXacts(builder, buf->origptr, running,
+											 !ctx->options.need_shared_catalogs);
 
 				/*
 				 * Abort all transactions that we keep track of, that are
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index f20d0c542f3..8ceaf64d164 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -285,6 +285,9 @@ StartupDecodingContext(List *output_plugin_options,
 	ctx->write = do_write;
 	ctx->update_progress = update_progress;
 
+	/* Assume shared catalog access. The startup callback can change it. */
+	ctx->options.need_shared_catalogs = true;
+
 	ctx->output_plugin_options = output_plugin_options;
 
 	ctx->fast_forward = fast_forward;
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index b4269a3b102..a6738e120c7 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -125,6 +125,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "access/genam.h"
 #include "access/heapam_xlog.h"
 #include "access/transam.h"
 #include "access/xact.h"
@@ -154,6 +155,14 @@
 static ResourceOwner SavedResourceOwnerDuringExport = NULL;
 static bool ExportInProgress = false;
 
+/*
+ * If a backend is going to do logical decoding and the output plugin does
+ * not need to access shared catalogs, setting this variable to false can make
+ * the decoding startup faster. In particular, the backend will not need to
+ * wait for completion of already running transactions in other databases.
+ */
+bool		accessSharedCatalogsInDecoding = true;
+
 /* ->committed and ->catchange manipulation */
 static void SnapBuildPurgeOlderTxn(SnapBuild *builder);
 
@@ -170,7 +179,8 @@ static inline bool SnapBuildXidHasCatalogChanges(SnapBuild *builder, Transaction
 												 uint32 xinfo);
 
 /* xlog reading helper functions for SnapBuildProcessRunningXacts */
-static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running);
+static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn,
+								  xl_running_xacts *running, bool db_specific);
 static void SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff);
 
 /* serialization functions */
@@ -1136,7 +1146,8 @@ SnapBuildXidHasCatalogChanges(SnapBuild *builder, TransactionId xid,
  * anymore.
  */
 void
-SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running)
+SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running,
+							 bool db_specific)
 {
 	ReorderBufferTXN *txn;
 	TransactionId xmin;
@@ -1149,7 +1160,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	if (builder->state < SNAPBUILD_CONSISTENT)
 	{
 		/* returns false if there's no point in performing cleanup just yet */
-		if (!SnapBuildFindSnapshot(builder, lsn, running))
+		if (!SnapBuildFindSnapshot(builder, lsn, running, db_specific))
 			return;
 	}
 	else
@@ -1166,8 +1177,14 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * (see SnapBuildCommitTxn).  Because of this, xmax can be lower than
 	 * xmin, which looks odd but is correct and actually more efficient, since
 	 * we hit fast paths in heapam_visibility.c.
+	 *
+	 * If database specific transaction info was used during startup, the info
+	 * for the whole cluster can make xmin go backwards. That would be bad
+	 * because we might no longer have older XIDs in ->committed.
 	 */
-	builder->xmin = running->oldestRunningXid;
+	if (!db_specific ||
+		NormalTransactionIdFollows(running->oldestRunningXid, builder->xmin))
+		builder->xmin = running->oldestRunningXid;
 
 	/* Remove transactions we don't need to keep track off anymore */
 	SnapBuildPurgeOlderTxn(builder);
@@ -1182,7 +1199,11 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * the record we're reading now.
 	 */
 	xmin = ReorderBufferGetOldestXmin(builder->reorder);
-	if (xmin == InvalidTransactionId)
+
+	/*
+	 * Like above, do not let slot xmin go backwards.
+	 */
+	if (xmin == InvalidTransactionId && !db_specific)
 		xmin = running->oldestRunningXid;
 	elog(DEBUG3, "xmin: %u, xmax: %u, oldest running: %u, oldest xmin: %u",
 		 builder->xmin, builder->xmax, running->oldestRunningXid, xmin);
@@ -1238,7 +1259,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
  * using the xl_running_xacts record.
  */
 static bool
-SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running)
+SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running,
+					  bool db_specific)
 {
 	/* ---
 	 * Build catalog decoding snapshot incrementally using information about
@@ -1265,6 +1287,25 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 * ---
 	 */
 
+	if (db_specific)
+	{
+		/*
+		 * If we must only keep track of transactions running in the current
+		 * database, we need transaction info from exactly that database.
+		 */
+		if (running->dbid != MyDatabaseId)
+		{
+			LogStandbySnapshot(MyDatabaseId);
+			return false;
+		}
+
+		/*
+		 * We'd better be able to check during scan if the plugin does not
+		 * lie.
+		 */
+		accessSharedCatalogsInDecoding = false;
+	}
+
 	/*
 	 * xl_running_xacts record is older than what we can use, we might not
 	 * have all necessary catalog rows anymore.
@@ -1465,7 +1506,11 @@ SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff)
 	 */
 	if (!RecoveryInProgress())
 	{
-		LogStandbySnapshot();
+		/*
+		 * If the last transaction info was about specific database, so needs
+		 * to be the next one - at least until we're in the CONSISTENT state.
+		 */
+		LogStandbySnapshot(running->dbid);
 	}
 }
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a9092fc2382..9533515a63b 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1762,7 +1762,7 @@ ReplicationSlotReserveWal(void)
 		XLogRecPtr	flushptr;
 
 		/* make sure we have enough information to start */
-		flushptr = LogStandbySnapshot();
+		flushptr = LogStandbySnapshot(InvalidOid);
 
 		/* and make sure it's fsynced to disk */
 		XLogFlush(flushptr);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index cc207cb56e3..92ed34128e5 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2631,9 +2631,11 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
  *
  * Note that if any transaction has overflowed its cached subtransactions
  * then there is no real need include any subtransactions.
+ *
+ * If 'dbid' is valid, only gather transactions running in that database.
  */
 RunningTransactions
-GetRunningTransactionData(void)
+GetRunningTransactionData(Oid dbid)
 {
 	/* result workspace */
 	static RunningTransactionsData CurrentRunningXactsData;
@@ -2708,6 +2710,18 @@ GetRunningTransactionData(void)
 		if (!TransactionIdIsValid(xid))
 			continue;
 
+		/*
+		 * Filter by database OID if requested.
+		 */
+		if (OidIsValid(dbid))
+		{
+			int			pgprocno = arrayP->pgprocnos[index];
+			PGPROC	   *proc = &allProcs[pgprocno];
+
+			if (proc->databaseId != dbid)
+				continue;
+		}
+
 		/*
 		 * Be careful not to exclude any xids before calculating the values of
 		 * oldestRunningXid and suboverflowed, since these are used to clean
@@ -2758,6 +2772,12 @@ GetRunningTransactionData(void)
 			PGPROC	   *proc = &allProcs[pgprocno];
 			int			nsubxids;
 
+			/*
+			 * Filter by database OID if requested.
+			 */
+			if (OidIsValid(dbid) && proc->databaseId != dbid)
+				continue;
+
 			/*
 			 * Save subtransaction XIDs. Other backends can't add or remove
 			 * entries while we're holding XidGenLock.
@@ -2791,6 +2811,7 @@ GetRunningTransactionData(void)
 	 * increases if slots do.
 	 */
 
+	CurrentRunningXacts->dbid = dbid;
 	CurrentRunningXacts->xcnt = count - subcount;
 	CurrentRunningXacts->subxcnt = subcount;
 	CurrentRunningXacts->subxid_status = suboverflowed ? SUBXIDS_IN_SUBTRANS : SUBXIDS_IN_ARRAY;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index de9092fdf5b..c653ea742bc 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1188,6 +1188,14 @@ standby_redo(XLogReaderState *record)
 		xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
 		RunningTransactionsData running;
 
+		/*
+		 * Records issued for specific database are not suitable for physical
+		 * replication because that affects the whole cluster. In particular,
+		 * the list of XID is probably incomplete here.
+		 */
+		if (OidIsValid(xlrec->dbid))
+			return;
+
 		running.xcnt = xlrec->xcnt;
 		running.subxcnt = xlrec->subxcnt;
 		running.subxid_status = xlrec->subxid_overflow ? SUBXIDS_MISSING : SUBXIDS_IN_ARRAY;
@@ -1277,11 +1285,12 @@ standby_redo(XLogReaderState *record)
  * as there's no independent knob to just enable logical decoding. For
  * details of how this is used, check snapbuild.c's introductory comment.
  *
+ * If 'dbid' is valid, only gather transactions running in that database.
  *
  * Returns the RecPtr of the last inserted record.
  */
 XLogRecPtr
-LogStandbySnapshot(void)
+LogStandbySnapshot(Oid dbid)
 {
 	XLogRecPtr	recptr;
 	RunningTransactions running;
@@ -1314,7 +1323,7 @@ LogStandbySnapshot(void)
 	 * Log details of all in-progress transactions. This should be the last
 	 * record we write, because standby will open up when it sees this.
 	 */
-	running = GetRunningTransactionData();
+	running = GetRunningTransactionData(dbid);
 
 	/*
 	 * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
@@ -1358,6 +1367,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
 	xl_running_xacts xlrec;
 	XLogRecPtr	recptr;
 
+	xlrec.dbid = CurrRunningXacts->dbid;
 	xlrec.xcnt = CurrRunningXacts->xcnt;
 	xlrec.subxcnt = CurrRunningXacts->subxcnt;
 	xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY);
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index b69320a7fc8..c9a52277be1 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -136,6 +136,13 @@ typedef struct IndexOrderByDistance
 	bool		isnull;
 } IndexOrderByDistance;
 
+
+/*
+ * Keep track of whether logical decoding in this backend promised not to
+ * access shared catalogs, as a safety check.  Somewhat misplaced, but ...
+ */
+extern bool accessSharedCatalogsInDecoding;
+
 /*
  * generalized index_ interface routines (in indexam.c)
  */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 10c18d39ff8..13ae3ad4fbb 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -32,7 +32,7 @@
 /*
  * Each page of XLOG file has a header like this:
  */
-#define XLOG_PAGE_MAGIC 0xD11E	/* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD11F	/* can be used as WAL version indicator */
 
 typedef struct XLogPageHeaderData
 {
diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h
index 842fcde67f9..917f3cff232 100644
--- a/src/include/replication/output_plugin.h
+++ b/src/include/replication/output_plugin.h
@@ -27,6 +27,7 @@ typedef struct OutputPluginOptions
 {
 	OutputPluginOutputType output_type;
 	bool		receive_rewrites;
+	bool		need_shared_catalogs;
 } OutputPluginOptions;
 
 /*
diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h
index a22a83a2f23..d02530a912a 100644
--- a/src/include/replication/snapbuild.h
+++ b/src/include/replication/snapbuild.h
@@ -92,7 +92,8 @@ extern void SnapBuildProcessNewCid(SnapBuild *builder, TransactionId xid,
 								   XLogRecPtr lsn,
 								   xl_heap_new_cid *xlrec);
 extern void SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn,
-										 xl_running_xacts *running);
+										 xl_running_xacts *running,
+										 bool db_specific);
 extern void SnapBuildSerializationPoint(SnapBuild *builder, XLogRecPtr lsn);
 
 extern bool SnapBuildSnapshotExists(XLogRecPtr lsn);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index abdf021e66e..377b3060b9f 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -49,7 +49,7 @@ extern bool ProcArrayInstallImportedXmin(TransactionId xmin,
 										 VirtualTransactionId *sourcevxid);
 extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc);
 
-extern RunningTransactions GetRunningTransactionData(void);
+extern RunningTransactions GetRunningTransactionData(Oid dbid);
 
 extern bool TransactionIdIsInProgress(TransactionId xid);
 extern TransactionId GetOldestNonRemovableTransactionId(Relation rel);
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 6a314c693cd..8715c08e94f 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -126,6 +126,7 @@ typedef enum
 
 typedef struct RunningTransactionsData
 {
+	Oid			dbid;			/* only track xacts in this database */
 	int			xcnt;			/* # of xact ids in xids[] */
 	int			subxcnt;		/* # of subxact ids in xids[] */
 	subxids_array_status subxid_status;
@@ -143,7 +144,7 @@ typedef RunningTransactionsData *RunningTransactions;
 extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
 extern void LogAccessExclusiveLockPrepare(void);
 
-extern XLogRecPtr LogStandbySnapshot(void);
+extern XLogRecPtr LogStandbySnapshot(Oid dbid);
 extern void LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
 									bool relcacheInitFileInval);
 
diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h
index 231d251fd51..e75b7078766 100644
--- a/src/include/storage/standbydefs.h
+++ b/src/include/storage/standbydefs.h
@@ -46,6 +46,7 @@ typedef struct xl_standby_locks
  */
 typedef struct xl_running_xacts
 {
+	Oid			dbid;			/* only track xacts in this database */
 	int			xcnt;			/* # of xact ids in xids[] */
 	int			subxcnt;		/* # of subxact ids in xids[] */
 	bool		subxid_overflow;	/* snapshot overflowed, subxids missing */
-- 
2.47.3


--qr3jlalmmcpkiodg
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
	filename="v53-0002-Fix-a-few-problems-in-index-build-progress-repor.patch"



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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

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


--s/7v445LwpBnK/Gl--





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

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

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

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

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

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

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

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

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2390+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email protected]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1


--s/7v445LwpBnK/Gl--





^ permalink  raw  reply  [nested|flat] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ 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; 2390+ 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] 2390+ messages in thread


end of thread, other threads:[~2026-04-23 09:27 UTC | newest]

Thread overview: 2390+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
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 ` Tom Lane <[email protected]>
2024-03-04 06:10   ` Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 08:09 ` Alvaro Herrera <[email protected]>
2024-03-04 09:50   ` Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 11:52     ` 'Alvaro Herrera' <[email protected]>
2024-03-04 13:11       ` Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 13:50         ` 'Alvaro Herrera' <[email protected]>
2024-03-05 02:00           ` Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-05 07:34             ` 'Alvaro Herrera' <[email protected]>
2026-04-04 15:16 [PATCH v53 1/7] Introduce an option to make logical replication database specific. Antonin Houska <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox